package com.join.template.html.grammar;

import com.join.template.core.constant.Constant;
import com.join.template.core.constant.EntityType;
import com.join.template.core.factory.JoinFactory;
import com.join.template.core.grammar.generate.AbstractGenerateGrammar;
import com.join.template.core.grammar.generate.Generate;
import com.join.template.core.grammar.handle.Grammar;
import com.join.template.core.grammar.info.FieldGenerateInfo;
import com.join.template.core.grammar.info.GrammarInfo;
import com.join.template.core.util.Assert;
import com.join.template.core.util.TemplateException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author CAOYOU
 * @Title: MapGenerate
 * @date 2019/10/2110:13
 */
public class MapGenerate extends AbstractGenerateGrammar<Map, Map> implements Generate<Map, Map> {

    public MapGenerate(JoinFactory joinFactory) {
        super(joinFactory);

    }

    @Override
    public Generate generate(String name, EntityType type, String describe, List<Map> child) {
        try {
            GrammarInfo grammarInfo = this.grammarInfoClass.newInstance();
            Map map = new HashMap();
            map.put(this.generateConfig.getNameKey(), name);
            map.put(this.generateConfig.getTypeKey(), type.name().toLowerCase());
            map.put(this.generateConfig.getDescribeKey(), describe);
            map.put(this.generateConfig.getChildKey(), child);
            this.createGrammarInfo(grammarInfo, map);
            grammarInfos.add(grammarInfo);
            return this;
        } catch (InstantiationException e) {
            throw new TemplateException("语法生成失败", e);
        } catch (IllegalAccessException e) {
            throw new TemplateException("语法生成失败", e);
        }
    }

    @Override
    public Generate generate(Map bean) {
        try {
            GrammarInfo grammarInfo = this.grammarInfoClass.newInstance();
            this.createGrammarInfo(grammarInfo, bean);
            return this;
        } catch (InstantiationException e) {
            throw new TemplateException("语法生成失败", e);
        } catch (IllegalAccessException e) {
            throw new TemplateException("语法生成失败", e);
        }
    }

    /**
     * 创建字段对应语法信息
     *
     * @param current
     * @param map
     * @return void
     * @author CAOYOU/625954232@qq.com
     * @date 2019/8/21 16:18
     */
    private void createGrammarInfo(GrammarInfo current, Map map) throws IllegalAccessException, InstantiationException {
        Object name = map.get(this.generateConfig.getNameKey());
        Assert.isNull(name, "缺少字段名称对应的键");

        Object type = map.get(this.generateConfig.getTypeKey());
        Assert.isNull(type, "缺少字段类型对应的键");

        Object describe = map.get(this.generateConfig.getDescribeKey());
        Assert.isNull(describe, "缺少字段描述对应的键");

        List<Map> childs = (List<Map>) map.get(this.generateConfig.getChildKey());

        current.setName(name.toString());
        current.setType(EntityType.of(type.toString()));
        current.setDescribe(describe.toString());

        if (this.generateListener != null) {
            this.generateListener.onGenerate(current, map, this.generateConfig);
        }

        if (EntityType.Array == current.getType()) {
            current.setGrammarType(Constant.EXPR_LIST);
        } else {
            current.setGrammarType(Constant.EXPR_VAR);
        }

        Grammar grammar = joinFactory.getGrammar(current.getGrammarType());
        Assert.isNull(type, "为找到对应语法的处理器：" + current.getGrammarType());

        String example = grammar.getExample().genExample(current);
        Assert.isNull(type, "该字段语法生成失败：" + name);
        current.setGrammar(example);

        if (childs != null) {
            this.createGrammarChild(current, childs);
        }
    }

    /**
     * 创建子集字段对应语法信息
     *
     * @param current
     * @param childs
     * @return void
     * @author CAOYOU/625954232@qq.com
     * @date 2019/8/21 16:17
     */
    private void createGrammarChild(GrammarInfo current, List<Map> childs) throws InstantiationException, IllegalAccessException {
        if (EntityType.Array == current.getType() || EntityType.Entity == current.getType()) {
            for (Map item : childs) {
                GrammarInfo grammarInfo = this.grammarInfoClass.newInstance();
                grammarInfo.setParentName(current.getName());
                grammarInfo.setParentType(current.getType());
                this.createGrammarInfo(grammarInfo, item);
                current.addChild(grammarInfo);
            }
        } else {
            throw new TemplateException("错误的集合：" + current.getName());
        }
    }

}
